package jp.ac.waseda.cs.washi.game.ai;

//PlayerAction.LEFT を LEFT と記述できるようにする宣言
import static jp.ac.waseda.cs.washi.game.api.PlayerAction.*;

import java.util.LinkedList;

import jp.ac.waseda.cs.washi.game.api.CharaInfo;
import jp.ac.waseda.cs.washi.game.api.GameInfo;
import jp.ac.waseda.cs.washi.game.api.MapInfo;
import jp.ac.waseda.cs.washi.game.api.Player;
import jp.ac.waseda.cs.washi.game.api.PlayerAction;
import jp.ac.waseda.cs.washi.gameaiarena.api.Direction4;
import jp.ac.waseda.cs.washi.gameaiarena.api.Point2;

public class MiniPumpkinMaker implements Player {
	private static CharaInfo player;
	private static MapInfo map;
	private static int h;
	private static int w;
	private static LinkedList<PlayerAction> commandList = new LinkedList<PlayerAction>();
	private static Direction4[] directions;
	// ミニパンプキンを作成する為のコマンド
	private static PlayerAction[] makeMiniPumpkinCmd = { UP, RIGHT, RIGHT,
			SPELL, SPELL, SPELL, SPELL, RIGHT, UP, SPELL, SPELL, SPELL, SPELL,
			LEFT, SPELL, SPELL, SPELL, SPELL, LEFT, SPELL, SPELL, SPELL, SPELL,
			UP, RIGHT, SPELL, SPELL, SPELL, SPELL };

	@Override
	public void initialize(GameInfo env) {
		map = env.getMap();
		player = env.getPlayer();
		h = map.getHeight();
		w = map.getWidth();
		return;
	}

	@Override
	public PlayerAction execute(GameInfo gameEnvironmentInfo) {
		// ゲームに必要な変数を初期化するメソッド
		initialize(gameEnvironmentInfo);
		// コマンドリストにコマンドがなければコマンドを追加する
		if (commandList.size() == 0) {
			// ミニパンプキンを作り始める事が出来る位置を検索する
			Point2 startPoint = searchStartPoint();
			// ミニパンプキンを作るスペースがなければ何もしない
			if (startPoint == null)
				return NONE;
			// ミニパンプキンを作る初期位置へ移動する為のコマンドをcommandListに追加する
			moveTo(startPoint);
			// ミニパンプキンを作る為のコマンドをcommandListに追加する
			makeMiniPumpkin();
		}
		// コマンドリストにコマンドがあった場合、逐次そのコマンドを実行する
		return commandList.remove(0);
	}

	// ミニパンプキンを作り始める位置を返却するメソッド（左上から検索）
	public static Point2 searchStartPoint() {
		for (int i = 0; i < w; i++) {
			for (int j = 0; j < h; j++) {
				Point2 p = new Point2(i, j);
				if (map.isMovable(p) && canMakeMiniPumpkin(p))
					return p;
			}
		}
		return null;
	}

	// 指定された位置からミニパンプキンを作成可能かどうかを返すメソッド
	public static boolean canMakeMiniPumpkin(Point2 p) {
		if (!map.isMovable(p))
			return false;
		// 検索位置移動用の配列
		int[] x = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
				0, 1, 2, 3, 4 };
		int[] y = { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3,
				-3, -3, -3, -3, -4, -4, -4, -4, -4 };
		Point2 dp;
		// 検索位置から右上に向かって5×5マスが空いているかを調べる
		for (int i = 0; i < x.length; i++) {
			dp = p.add(new Point2(x[i], y[i]));
			if (map.getCompleteOwner(dp) != null || !map.canDevelop(dp)
					|| !map.isMovable(dp))
				return false;
		}
		return true;
	}

	// 現在位置から指定位置へ移動するコマンドをcommandListに追加するメソッド
	public static void moveTo(Point2 p) {
		directions = map.getPath(player.getLocation(), p);
		for (Direction4 dir : directions)
			commandList.add(PlayerAction.fromDirection(dir));
		return;
	}

	// 現在位置から右上に向かってミニパンプキンを作成するコマンドをcommandListに追加するメソッド
	public static void makeMiniPumpkin() {
		for (int i = 0; i < makeMiniPumpkinCmd.length; i++)
			commandList.add(makeMiniPumpkinCmd[i]);
		return;
	}
}
